/*
 * Copyright (c) 2009 Nathaniel Houghton <nathan@brainwerk.org>
 *                    Robert Kirchgessner <rkirchge@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for
 * any purpose with or without fee is hereby granted, provided that
 * the above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <stdio.h>
#include <string.h>
#include <windows.h>

#include "ui.h"
#include "menu_res.h"

#define DEBOUNCE_DELAY 20

#define SW_MSK 0x1E
#define LCD_MSK 0x01

#define _delay_us(A) Sleep(A)

static struct menu ui_menu;
static volatile uint8_t buttons;

static uint8_t PORTA;
static uint8_t PORTD;
static uint8_t PCMSK0;
static uint8_t PCMSK3;
static uint8_t PCICR;
static uint8_t PINA;
static uint8_t PIND;

void menu_set_current( uint8_t );
void menu_add_static( const struct static_menu_entry * );
void menu_add_dynamic( const struct dynamic_menu_entry * );
struct menu_entry *menu_get_entry( uint8_t id );

#define BUTTON_LEFT BTN_3
#define BUTTON_RIGHT BTN_1
#define BUTTON_ENTER BTN_2

void
menu(void)
{
	char c;
	struct menu_entry * current;
	struct static_menu_entry * static_current;
	struct dynamic_menu_entry * dynamic_current;
	
	static uint8_t update = 1;

	current = menu_get_entry( ui_menu.current ); /*Get the current menu entry*/
	
	if( update ) 
	{
		if( current->type == MENU_ENTRY_STATIC ) /*Static menus have a constant string*/
		{
			static_current = (struct static_menu_entry*)current;
			lcd_update(&lcd, 1,  static_current->disp );	
		}
		else if( current->type == MENU_ENTRY_DYNAMIC ) /*Static menus have output strings generated by functions*/
		{
			dynamic_current = (struct dynamic_menu_entry*)current;
			dynamic_current->disp();
		}
		update = 0;
	}
	
	while( (c=getc(stdin)) != '\n' )
	{
			if( c== 'l' )
				buttons |= 0x1;
			
			if( c=='r' )
				buttons |= 0x2;
			
			if( c== 'x' )
				buttons |= 0x4;
	}	
	
	if ( btn_down(BUTTON_LEFT) )
	{
		if(current->left != ui_menu.current )
		{
			update = 1;	
			menu_set_current( current->left );
		}
		
	}

	if ( btn_down(BUTTON_ENTER) )
	{
		if(current->enter != ui_menu.current )
		{
			update = 1;
			menu_set_current( current->enter );	
		}
		
		if( current->fp != NULL ) /*If there is a function to be executed on enter button, then run it*/
			current->fp();
	}

	if ( btn_down(BUTTON_RIGHT) )
	{
		if(current->right != ui_menu.current )
		{
			update = 1;
			menu_set_current( current->right );	
		}
	}
	

}

void
init_ui(void)
{
	/* enable pull-up resistors */
	PORTA |= 0xF0;
	PORTD |= 0x80;

	_delay_us(30);

	/* mask off pins of interest for b3..1 */
	PCMSK0 = 0xF0;

	/* enable PCINT0 for b3..1 */
	PCICR |= 0x01;
	
	/* mask off pins of interest for lcd_present */
	PCMSK3 = 0x80;

	/* enable PCINT3 for lcd_present */
	PCICR |= 0x08;
	

	menu_add_static( &MENU_RES_NAME(MENU_ID_ROOT) );
	menu_add_static( &MENU_RES_NAME(MENU_ID_CHECK_DTC) );	
	menu_set_current( MENU_ID_ROOT );
}



uint8_t
btn_down(uint8_t btn)
{
	
	if((buttons & 0x1 ) && btn == BTN_3)
	{
		buttons &= ~0x1;
		return 1;
	}
		
	if((buttons & 0x2 )&& btn == BTN_1)
	{
		buttons &= ~0x2;
		return 1;
	}
	
	if((buttons & 0x4 )&& btn == BTN_2)
	{
		buttons &= ~0x4;
		return 1;
	}
	
	
	return 0;
}

void menu_set_current( uint8_t id )
{
	ui_menu.current = id;
}

void 
menu_add_static( const struct static_menu_entry * entry )
{
	ui_menu.menu_entries[ ui_menu.length ] = (struct menu_entry*)entry;
	ui_menu.length++;
}

void 
menu_add_dynamic( const struct dynamic_menu_entry * entry)
{
	ui_menu.menu_entries[ ui_menu.length ] = (struct menu_entry*)entry;
	ui_menu.length++;
}

struct menu_entry *
menu_get_entry( uint8_t id )
{
	int i;
	
	for(i=0;i<MENU_ENTRY_COUNT;++i)
	{
		if( ui_menu.menu_entries[i]->id == id )
			break;
	}

	return ui_menu.menu_entries[i];
}

